'''
图中共有15个空心圆点，x轴是日期，格式是xx月xx日。y轴是数值，最小值是476.0，最大值是1600.
从图中直接肉眼观察估计：
01-27，Y数值应该小于1200；
02-21，Y数值应该大于1000；
03-18，Y数值是600~800之间；
04-12，Y数值应该小于600，大于476；
05-08，Y数值应该476；
06-03，Y数值应该476~600之间；
06-28，Y数值应该476~600之间；
07-24，Y数值应该是600；
08-19，Y数值应该800~1000之间；
09-13，Y数值应该1200~1400之间；
10-09，Y数值应该是1600；
11-04，Y数值应该是1400~1600之间；
11-29，Y数值应该是1400~1600之间；
12-31，Y数值应该是1200~1400之间；
用python3.10，编写程序，实现根据（附件）提供的随意给出的折线图，反向推导出x,y轴的[x,y]坐标数据。

circle_points:
[('01-01', 1355), ('01-27', 1180), ('02-21', 1060), ('03-18', 720),
('04-12', 550), ('05-08', 476), ('06-03', 540), ('06-28', 510),
('07-24', 600), ('08-19', 920), ('09-13', 1300), ('10-09', 1600),
('11-04', 1500), ('11-29', 1480), ('12-31', 1330)]
'''
import cv2
import numpy as np

# X轴映射函数 
def map_x(x):
  dates = ['01-01', '01-27', '02-21', '03-18', '04-12', '05-08', 
         '06-03', '06-28', '07-24', '08-19', '09-13', '10-09',
         '11-04', '11-29', '12-31']  
  '''
  import datetime

  start = datetime.date(2023, 1, 1)
  end = datetime.date(2023, 12, 31)
  dates = [start + datetime.timedelta(days=x) for x in range((end - start).days)]
  dates = [date.strftime('%m-%d') for date in dates]
  '''
  date_width = img.shape[1] / len(dates)
  x = x[0] 
  # 再转换成整数索引
  x = int((x / date_width)[0])  
  return dates[x]

# Y轴映射函数
def map_y_err(y):
  refs = np.array([476, 600, 800, 1000, 1200, 1400, 1600])
  min_ref = 476
    # max_ref = 1600
    # interval = 200
    # refs = [min_ref + i*interval for i in range((max_ref - min_ref) // interval + 1)]  
  ref_height = img.shape[0] / len(refs)

  y = y[0][0]
  y_idx = int(y / ref_height)
  if y_idx == len(refs) - 1 or y_idx + 1 >= len(refs):
    return refs[y_idx] 
  next_idx = min(y_idx+1, len(refs)-1)
  return refs[y_idx] + (y/ratio - y_idx) * (refs[next_idx] - refs[y_idx])

# Y轴映射函数  
def map_y_xxx(y):     
  refs = np.array([476, 600, 800, 1000, 1200, 1400, 1600]) # 修改为实际Y轴数据范围的NumPy数组
  print(refs.shape)  
  ref_height = img.shape[0] / (refs.max() - refs.min()) # 计算Y轴数据范围和图像高度的比例  
#   y_idx = int((y - refs.min()) * ref_height) # 根据Y值计算索引  
  y_idx = int((y - refs.min(axis=0)) * ref_height) # 根据Y值计算索引
  return refs[y_idx] # 根据索引返回对应的Y轴数据

def map_y(y, y_min=476, y_max=1600):
  ratio = (y_max - y_min) / img.shape[0]
  y = (y / ratio + y_min)[0][1]
  return y

# 读取图像并转成灰度图
img = cv2.imread('line_plot.png') 
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# 图像处理,获取折线图轮廓
blur = cv2.GaussianBlur(gray, (3,3), 0)
edges = cv2.Canny(blur, 50, 200)
contours, _ = cv2.findContours(edges, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)

# 提取坐标点
points = []
for c in contours:
    for p in c:
        points.append(tuple(p[0]))

# 映射 x 轴的日期
dates = ['01-01', '01-27', '02-21', '03-18', '04-12', '05-08', 
         '06-03', '06-28', '07-24', '08-19', '09-13', '10-09',
         '11-04', '11-29', '12-31'] 
date_width = img.shape[1] / len(dates)

x_values = [dates[int(p[0]/date_width)] for p in points]

# 映射 y 轴的参考值  
refs = [476, 600, 800, 1000, 1200, 1400, 1600]
ref_height = img.shape[0] / len(refs)

y_values = [refs[int(p[1]/ref_height)] for p in points] 

# 寻找和提取圆点
circles = cv2.findContours(edges, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE) 

circle_points = []
for c in circles:
   # 计算圆心并映射到日期、参考值
   x = map_x(c[0][0])  
   y = map_y(c[0][1])
   circle_points.append((x, y))

print(x_values)
print(y_values)
print(circle_points)